package com.example.common.sendhttp;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.example.common.support.ApiException;
import com.example.common.utils.MapUtils;
import com.google.gson.GsonBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * ca 调用接口类
 *
 * @Author rlj
 * @Date 2021/4/7 13:40
 * @Version 1.0
 */
@Component
public class CaSendMessage {

    /**
     * 第三方ca 的前置url
     */
    private static final String URL = "https://api-sit.isignet.cn:8082/";

    /**
     * ca 申请的appid
     */
    private static final String APP_ID = "67f6c99b74484c2b8bcb35473850cdd7";

    /**
     * ca 的 deviceId
     */
    private static final String DEVICE_ID = "DEV_B90213F1BAD64B7AA139724161E3B339";

    /**
     * ca 接入参数
     */
    private static final String SECRET = "MBxCw0HP7kEVhvC5QL4Da74gzDL7chfU";

    /**
     * 常量字符串
     */
    private static final String AND = "&";

    /**
     * 常量字符串
     */
    private static final String EQUAL = "=";


    /**
     * 用户未激活状态
     */
    public static final String NOT_ACTIVE = "NOT_ACTIVE";

    /**
     * 用户不存在或已促销
     */
    public static final String NOT_EXIST = "NOT_EXIST";

    /**
     * 用户冻结
     */
    public static final String LOCKED = "LOCKED";

    /**
     * 用户已激活
     */
    public static final String ACTIVE = "ACTIVE";

    public static final String SUCCESS = "SUCCESS";

    public static final String MESSAGE = "message";

    /**
     * 添加信任用户调用
     *
     * @param name   用户姓名
     * @param idType 用户证件类型SF-身份证；HZ-护照
     * @param idNum  证件号码
     * @param mobile 手机号
     * @return {"status":200,"message":"SUCCESS","data": { "msspId":用户编号, "authCode":授权码, "qrCode": 二维码信息}}
     */
    public String addTrustedUser(String name, String idType, String idNum, String mobile) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(9));
        map.put("name", name);
        map.put("idType", idType);
        map.put("idNum", idNum);
        map.put("mobile", mobile);
        return goToHttp("MSSPServer/biz/user/v1/addTrustedUser ", map);
    }


    /**
     * 查询用户
     *
     * @param msspId ca用户编号
     * @return NOT_EXIST：用户信息不存在或已注销
     * LOCKED：用户被冻结
     * ACTIVE：用户已经激活
     * NOT_ACTIVE：用户尚未激活
     */
    public String queryUserInfo(String msspId) {
        Map<String, String> map = new HashMap<>();
        map.put("msspId", msspId);
        return goToHttp("MSSPServer/biz/user/v1/queryUserInfo", map);
    }

    /**
     * 根据用户身份证查询
     *
     * @param idNum 身份证号
     * @return 返回调用信息
     */
    public String idNumQueryUserInfo(String idNum) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(2));
        map.put("idType", "SF");
        map.put("idNum", idNum);
        return goToHttp("MSSPServer/biz/user/v1/queryUserInfo", map);
    }


    /**
     * 删除用户调用
     *
     * @param msspId ca返回的用户编号
     * @return 调用信息是否删除成功
     */
    public String deleteUser(String msspId) {
        Map<String, String> map = new HashMap<>();
        map.put("msspId", msspId);
        return goToHttp("MSSPServer/biz/user/v1/deleteUser", map);
    }

    /**
     * 更新用户的激活码
     *
     * @param msspId 用户编号
     * @return 调用信息
     */
    public String updateAuthCode(String msspId) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(6));
        map.put("msspId", msspId);
        String result = goToHttp("MSSPServer/biz/user/v1/updateAuthCode", map);
        JSONObject resultJson = JSONObject.parseObject(result);
        if (SUCCESS.equals(resultJson.get(MESSAGE))) {
            Object data = resultJson.get("data");
            JSONObject dataJson = JSONObject.parseObject(data.toString());
            return dataJson.get("authCode").toString();
        } else {
            throw new ApiException(HttpStatus.HTTP_INTERNAL_ERROR, resultJson.get(MESSAGE).toString());
        }
    }

    /**
     * 创建签名请求调用
     *
     * @param msspId 用户编号
     * @param data   代签的数据
     * @return 签名任务id
     */
    public String getSignJob(String msspId, String data) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(9));
        map.put("dataType", "PLAIN");
        map.put("jobSignAlgo", "SM3withSM2");
        map.put("msspId", msspId);
        String encode = Base64.encode(data);
        map.put("data", encode);
        return goToHttp("MSSPServer/biz/signjob/v1/addSignJob", map);
    }

    /**
     * 获得签名的结果
     *
     * @param signJobId 签名任务id
     * @return {"status":200,"message":"SUCCESS","data":{"signStatus":"任务状态","signCert":"签名证书","signData":"签名原文的base64","signResult":"签名值","msspId":"签名用户编号"}}
     * <p>
     * 任务状态说明：
     * WAITING_USER_SIGN：任务尚未签署
     * USER_SIGN_FINISH：任务签署完成，完成状态才能获取到签名结果
     * TIMEOUT：任务超期，已经无法签署
     */
    public String querySignJob(String signJobId) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(6));
        map.put("signJobId", signJobId);
        return goToHttp("MSSPServer/biz/signjob/v1/querySignJob", map);
    }

    /**
     * 时间签名
     *
     * @param data 签名的时间
     * @return 签名结果
     */
    public String signtss(String data) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(7));
        map.put("algo", "SM2");
        String encode = Base64.encode(data);
        map.put("data", encode);
        return goToHttp("tss/v1/signtss", map);
    }

    /**
     * 校验时间戳
     *
     * @param data         原文数据
     * @param tssSignature 签名值
     * @return 是否成功
     */
    public String verifytss(String data, String tssSignature) {
        Map<String, String> map = new HashMap<>(8);
        map.put("tssSignature", tssSignature);
        String encode = Base64.encode(data);
        map.put("algo", "SM2");
        map.put("data", encode);
        return goToHttp("tss/v1/verifytss", map);
    }

    /**
     * 校验签名是否成功
     *
     * @param plain      原文的base 64
     * @param signResult 签名结果
     * @param cert       证书
     * @return 返回是否签名成功
     */
    @GetMapping("/verifySign")
    public String verifySign(String plain, String signResult, String cert) {
        Map<String, String> map = new HashMap<>(MapUtils.getMapInitSize(9));
        map.put("dataSignAlgo", "SM3withSM2");
        map.put("plain", plain);
        map.put("signResult", signResult);
        map.put("cert", cert);
        return goToHttp("MSSPServer/biz/verify/v1/verifySign", map);
    }

    /**
     * 发起请求
     *
     * @param backUrl 后置url
     * @param map     参数
     * @return 返回请求结果
     */
    private String goToHttp(String backUrl, Map<String, String> map) {
        String url = URL + backUrl;
        Snowflake snowflake = IdUtil.getSnowflake(1, 1);
        long l = snowflake.nextId();
        map.put("version", "1.0");
        map.put("signAlgo", "HMAC");
        map.put("deviceId", DEVICE_ID);
        map.put("appId", APP_ID);
        map.put("transId", String.valueOf(l));
        try {
            String paramJson = generateRequestJson(map, SECRET);
            System.err.println("请求参数" + paramJson);
            return HttpUtil.post(url, paramJson);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }


    private String generateRequestJson(Map<String, String> request, String key) throws Exception {
        String data = generateSignString(request);

        String signature;
        signature = getHmac(data.getBytes(StandardCharsets.UTF_8), key.getBytes());

        request.put("signature", signature);
        return new GsonBuilder().disableHtmlEscaping().create().toJson(request);
    }


    /**
     * 生成签名字符串，忽略掉转入的属性名
     */
    private String generateSignString(Map<String, String> props) {

        StringBuilder sb = new StringBuilder();
        List<String> keys = new ArrayList<>(props.keySet());
        Collections.sort(keys);

        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            Object value = props.get(key);
            if (value == null || "signature".equals(key)) {
                continue;
            }

            // 拼接时，不包括最后一个&字符
            if (i == props.size() - 1) {
                sb.append(key).append(EQUAL).append(value);
            } else {
                sb.append(key).append(EQUAL).append(value).append(AND);
            }
        }
        return sb.toString();
    }

    private String getHmac(byte[] data, byte[] key) throws Exception {

        SecretKeySpec signingKey = new SecretKeySpec(key, "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        return Base64.encode(mac.doFinal(data));
    }
}
